Call listeners for running task instance when a Dag Run state is manually set#69874
Call listeners for running task instance when a Dag Run state is manually set#69874kacpermuda wants to merge 4 commits into
Conversation
a1ba686 to
d5ff798
Compare
amoghrajesh
left a comment
There was a problem hiding this comment.
Good investigation but some comments need handling
pierrejeambrun
left a comment
There was a problem hiding this comment.
Small nit, in addition of Amogh's comments
b9f98d3 to
8de2bf3
Compare
amoghrajesh
left a comment
There was a problem hiding this comment.
This looks like a genuine improvement from a listener's perspective, force-setting a Dag Run's state now fires on_task_instance_success/on_task_instance_failed for tasks that were actively running, closing the gap where a listener like OL would see a start event with no matching terminal event & for that reason I think its worth adding a newsfragment so this shows up in release notes for anyone relying on task-instance listeners. @pierrejeambrun any thoughts?
Rest of the changes LGTM.
8de2bf3 to
7cd2c68
Compare
|
Added newsfragment as requested, let me know if it needs adjustments |
When a task instance is individually set to success or failure via the API,
on_task_instance_success/on_task_instance_failedis called from the API server, giving listeners a terminal event to act on. The same does not happen when an entire Dag Run is force-set to success or failure: running tasks are bulk-transitioned in the database, but their task-instance listeners are never fired. Listeners that registered a start event (on_task_instance_running) for those tasks receive no completion event, leaving them — notably OpenLineage — with a job permanently stuck in RUNNING.This PR closes the gap:
_set_dag_run_terminal_statenow returns(all_updated_tis, running_tis)whererunning_tisis the snapshot of task instances that were in an active state (RUNNING, DEFERRED, UP_FOR_RESCHEDULE, AWAITING_INPUT) before the bulk transition, captured without an extra query.set_dag_run_state_to_success/set_dag_run_state_to_failedexpose the same tuple so callers have access to the running subset.patch_dag_run_statefireson_task_instance_success/on_task_instance_failedfor those running task instances before the dag-run-level hook. Each group has its owntry/exceptso a listener failure in one cannot suppress the other.Tasks that were only QUEUED or SCHEDULED (never started, no start event fired) are excluded — they transition to SKIPPED and receive no listener call, consistent with their lifecycle.
Why the terminal event is missing
The gap is a deliberate design decision that becomes a problem specifically for the dag run force-terminate case:
Result: on_task_instance_running fired from the task runner → task process killed → nothing on the other end. OpenLineage has a dangling RUNNING job with no terminal event. We can't extend the live of the worker process, but we can fire from the api server in that case.
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (claude-sonnet-4-6) following the guidelines
{pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.